<?php
/*******************************************************************
 * AmfV3Formatter.php
 * Copyright (C) 2006-2007 Midnight Coders, LLC
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is WebORB Presentation Server (R) for PHP.
 * 
 * The Initial Developer of the Original Code is Midnight Coders, LLC.
 * All Rights Reserved.
 ********************************************************************/



require_once(WebOrb . "Writer/IProtocolFormatter.php");
require_once(WebOrb . "Writer/FlashorbBinaryWriter.php");
require_once(WebOrb . "Writer/V3ObjectSerializer.php");
require_once(WebOrb . "Writer/V3ReferenceCache.php");
require_once(WebOrb . "Writer/MessageWriter.php");
require_once(WebOrb . "Writer/DateWriter.php");
require_once(WebOrb . "Writer/ORBDateTimeWriter.php");
require_once(WebOrb . "Message/Request.php");
require_once(WebOrb . "Util/Datatypes.php");
require_once(WebOrb . "Util/ORBDateTime.php");

class AmfV3Formatter
    implements IProtocolFormatter
{

    private $m_stream;
    private $m_writer;
    private $m_objectSerializer;
    private $m_referenceCache;

    public function __construct()
    {
        $this->m_stream = "";
        $this->m_writer = new FlashorbBinaryWriter($this->m_stream);
        $this->m_objectSerializer = new V3ObjectSerializer();
        $this->m_referenceCache = new V3ReferenceCache();
        MessageWriter::addTypeWriter( 'DateTime', new DateWriter( TRUE ) );
        MessageWriter::addTypeWriter( 'ORBDateTime', new ORBDateTimeWriter( TRUE ) );
    }

    public function getReferenceCache()
    {
        return $this->m_referenceCache;
    }

    public function resetReferenceCache()
    {
        $this->m_referenceCache->reset();
    }

    public function directWriteString($str)
    {
        $this->m_writer->writeUTF($str);
    }

    public function directWriteInt($i)
    {
        $this->m_writer->writeInt($i);
    }

    public function directWriteBoolean($b)
    {
        $this->m_writer->write($b);

            if( $b )
                $this->m_writer->write( Datatypes::BOOLEAN_DATATYPE_TRUEV3 );
            else
                $this->m_writer->write( Datatypes::BOOLEAN_DATATYPE_FALSEV3 );
    }

    public function directWriteShort($s)
    {
        $this->m_writer->writeShort($s);
    }

    public function beginWriteMessage(Request $message)
    {
    }

    public function endWriteMessage()
    {
    }

    public function writeMessageVersion($version)
    {
        $this->m_writer->writeShort($version);
    }

    public function beginWriteBodyContent()
    {
        $this->m_writer->write(Datatypes::V3_DATATYPE);
    }

    public function endWriteBodyContent()
    {

    }

    public function beginWriteArray($length)
    {

        $this->m_writer->write(Datatypes::ARRAY_DATATYPE_V3);
        $this->m_writer->writeVarInt($length << 1 | 0x1);
        $this->m_writer->writeVarInt(0x1);
    }

    public function endWriteArray()
    {

    }

    public function writeBoolean($b)
    {
        if ($b)
        {
            $this->m_writer->write(Datatypes::BOOLEAN_DATATYPE_TRUEV3);
        }
        else
        {
            $this->m_writer->write(Datatypes::BOOLEAN_DATATYPE_FALSEV3);
        }
    }

    public function writeDate(ORBDateTime $datetime)
    {
        $this->m_writer->write(Datatypes::DATE_DATATYPE_V3);
        $this->m_writer->writeVarInt(0x1);
        $this->m_writer->writeDouble($datetime->getTotalMs());
    }

    public function beginWriteObjectMap($size)
    {

        $this->m_writer->write(Datatypes::OBJECT_DATATYPE_V3);
        $this->m_writer->writeVarInt(0x3 | size << 4); // classInfo with size of the property count
        $this->m_writer->writeVarInt(1); // no classname
    }

    public function endWriteObjectMap()
    {

    }

    public function writeFieldName($s)
    {
        $this->m_writer->writeUTF($s, true);
    }

    public function beginWriteFieldValue()
    {
    }

    public function endWriteFieldValue()
    {
    }

    public function writeNull()
    {
        $this->m_writer->write(Datatypes::NULL_DATATYPE_V3);
    }

    public function writeNumber($number)
    {
        if (($number >= -268435456 && $number <= 268435455)
                && !is_double($number))
        {
            $this->m_writer->write(Datatypes::INTEGER_DATATYPE_V3);
            $this->m_writer->writeVarInt((integer) $number & 0x1fffffff);
        }
        else
        {
            $this->m_writer->write(Datatypes::DOUBLE_DATATYPE_V3);
            $this->m_writer->writeDouble($number);
        }
    }

    public function beginWriteNamedObject($objectName, $fieldCount = null)
    {
        $this->m_writer->write(Datatypes::OBJECT_DATATYPE_V3);
        $this->m_writer->writeVarInt(0x3 | $fieldCount << 4);

        if (is_null($objectName))
        {
            $this->m_writer->writeVarInt(1);
        }
        else
        {
            $this->m_writer->writeUTF($objectName, true);
        }
    }

    public function endWriteNamedObject()
    {

    }

    public function beginWriteObject($fieldCount = null)
    {
        $this->m_writer->write(Datatypes::OBJECT_DATATYPE_V3);
        $this->m_writer->writeVarInt(0x3 | fieldCount << 4);
        $this->m_writer->writeVarInt(0x1);
    }

    public function endWriteObject()
    {
    }

    public function writeArrayReference($refID)
    {
        $this->m_writer->write(Datatypes::ARRAY_DATATYPE_V3);
        $this->m_writer->writeVarInt($refID << 1);
    }

    public function writeObjectReference($refID)
    {
        $this->m_writer->write(Datatypes::OBJECT_DATATYPE_V3);
        $this->m_writer->writeVarInt($refID << 1);
    }

    public function writeStringReference($refID)
    {
        $this->m_writer->writeVarInt($refID << 1);
    }

    public function writeString($s)
    {
        $this->m_writer->write(Datatypes::UTFSTRING_DATATYPE_V3);
        $this->m_writer->writeUTF($s, true);
    }

    public function writeXML(DomDocument $document)
    {
        $writer->write(Datatypes::LONGXML_DATATYPE_V3);
        $this->m_writer->writeUTF($document->saveXML(), true);
    }

    public function getBytes()
    {
        return $this->m_stream;
    }
    public function cleanup()
    {
        $this->m_writer = "";
    }

    public function getContentType()
    {
        return "application/x-amf";
    }

    public function getObjectSerializer()
    {
        return $this->m_objectSerializer;
    }

    public function writeReference($refId)
    {

    }

}

?>
